package com.example.springboot_selenium_demo.util;

import com.example.springboot_selenium_demo.googleauth.GoogleAuthenticator;
import com.google.common.collect.ImmutableMap;

import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.openqa.selenium.remote.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.yandex.qatools.ashot.AShot;
import ru.yandex.qatools.ashot.shooting.ShootingStrategies;
import ru.yandex.qatools.ashot.shooting.ShootingStrategy;


import javax.imageio.ImageIO;
import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;



public class SellerCentral {
	/*
	 * =================开始=切换站点==============
	 */
	private ArrayList<MarketplaceHandler> marketplaceHandlers=new ArrayList<MarketplaceHandler>();
	public void putMarketplaceHandler(MarketplaceHandler marketplaceHandler) {
		marketplaceHandler.setDriver(driver);
		marketplaceHandler.setDesiredCapabilities(desiredCapabilities);
		marketplaceHandler.setBrowserSetting(browserSetting);
		marketplaceHandler.setBrowserName(browserName);
		marketplaceHandler.setaShot(aShot);
		marketplaceHandlers.add(marketplaceHandler);
	}
	
	public void traversalMarketplace() {
		List<WebElement> selectList = driver.findElements(By.id("sc-mkt-picker-switcher-select"));
		List<WebElement> optionList = selectList.get(0).findElements(By.xpath("//option[@class='sc-mkt-picker-switcher-select-option']"));
		ArrayList<String> marketplaceURLlist=new ArrayList<String>();
		//遍历获取所有国家的URL
		for (WebElement webElement : optionList) {
			String marketplace_url = webElement.getAttribute("value");
			marketplaceURLlist.add(marketplace_url);
		}
		
		//遍历获取到的URL
		for (String marketplace_url : marketplaceURLlist) {
			try {
				
				//解析URL,获取到marketplaceID
				Hashtable<String, String> splitParam = UrlHelper.splitParam(marketplace_url);
				String marketplaceId = splitParam.get("marketplaceId");
				String url=WebDriverHelper.getHostAndPort(driver).toString()+marketplace_url;
				
				//切换到国家,且判断是否切换成功,不成功返回true
				while (switchMarketplaceIfFailed(marketplaceId, url)) {
					Thread.sleep(3*1000);
				}
				logger.info("Switch marketplace[{}]", marketplaceId);
				
				//触发业务逻辑
				Iterator<MarketplaceHandler> marketplaceIterator = marketplaceHandlers.iterator();
				while (marketplaceIterator.hasNext()) {
					try {
						MarketplaceHandler iMarketplaceHandler = (MarketplaceHandler) marketplaceIterator.next();
						iMarketplaceHandler.jobInMarketplace(marketplaceId);	
					} catch (Exception e) {
						logger.error("Marketplace[{}] Failed", marketplaceId, e);
					}					
				}
			} catch (Exception e) {
				logger.error("Exception : ");
			}
		}
	}
	
	private boolean switchMarketplaceIfFailed(String marketplaceId, String url) {
		try {
			driver.get(url); 
			logger.info("Switch marketplace[{}]", marketplaceId);
			Thread.sleep(3*1000);
			
			//从页面获取当前的marketplace字符串,判断是否切换成功
			String current_marketplaceId = (String) driver.executeAsyncScript("var callback=arguments[arguments.length-1];callback(ue_mid)");
			logger.info("Current marketplace[{}]", current_marketplaceId);
			if(current_marketplaceId.trim().equals(marketplaceId)) {
				return false;
			}else {
				return true;
			}
		} catch (Exception e) {
		}
		return true;
	}
	
	public void switchMarketplace(String marketPlace) {
		try {
//			ShootingStrategy shootingStrategyViewportPasting = ShootingStrategies.viewportPasting(100);
//			AShot aShot = new AShot().shootingStrategy(shootingStrategyViewportPasting);
			System.err.println("switchMarketplace");
			boolean switchNotYet=true;
			while (switchNotYet) {
				List<WebElement> selectList = driver.findElements(By.id("sc-mkt-picker-switcher-select"));
				List<WebElement> optionList = selectList.get(0).findElements(By.xpath("//option[@class='sc-mkt-picker-switcher-select-option']"));
				for (WebElement webElement : optionList) {
					try {
						String marketplace_url = webElement.getAttribute("value");
						Hashtable<String, String> splitParam = UrlHelper.splitParam(marketplace_url);
						String marketplaceId = splitParam.get("marketplaceId");
						if (marketplaceId.equals(marketPlace)) {
							driver.get(WebDriverHelper.getHostAndPort(driver).toString()+marketplace_url); 
							logger.info("Switch marketplace[{}]", marketPlace);
							Thread.sleep(3*1000);
							
							//从页面获取当前的marketplace字符串,判断是否切换成功
							String current_marketplaceId = (String) driver.executeAsyncScript("var callback=arguments[arguments.length-1];callback(ue_mid)");
							logger.info("Current marketplace[{}]", current_marketplaceId);
							if (current_marketplaceId==null) {
								logger.info("ue_mid is return null");
								Thread.sleep(5*1000);
								break;
							}else {
								if(current_marketplaceId.trim().equals(marketPlace)) {
									switchNotYet=false;
								}else {
									logger.info("ue_mid is not match");
									Thread.sleep(5*1000);
									break;
								}
							}
						}
					} catch (Exception e) {
					}
				}
			}			
			if(!switchNotYet) {
				Iterator<MarketplaceHandler> marketplaceIterator = marketplaceHandlers.iterator();
				while (marketplaceIterator.hasNext()) {
					MarketplaceHandler iMarketplaceHandler = (MarketplaceHandler) marketplaceIterator.next();
					iMarketplaceHandler.jobInMarketplace(marketPlace);
				}	
			}			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	/*
	 * =================结束=切换站点==============
	 */
	
	private static final String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpJxKG1OEsVBaSYDlCOu8jiXKF95iP+ZzGSoNYJ7Ua5rLIJqkuHIx6trSYLOX87CjTi2YpDwNX/FGDBLnUxoZA3Gocm2ub2Ptj3KHQWNf+ySLD2u2uLMKFh4JcNIcmpD1jONeg5zBrLplIAHUEOwuwLcR1LTCSnHcpcPp9y/c8jwIDAQAB";
	private static final String privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKknEobU4SxUFpJgOUI67yOJcoX3mI/5nMZKg1gntRrmssgmqS4cjHq2tJgs5fzsKNOLZikPA1f8UYMEudTGhkDcahyba5vY+2PcodBY1/7JIsPa7a4swoWHglw0hyakPWM416DnMGsumUgAdQQ7C7AtxHUtMJKcdylw+n3L9zyPAgMBAAECgYBtZOeGa4Z0tK0kXTaqrpKZ2PpHyajQ9A1/8BChooxtqWVWLCqdt7jiY+bHw8G5oMGGjlCznRH8hSHyKcxE319S5f1aFDbOqyAm8E4kO77ZRw0+XOWoJbGGLs9d4IICb1Poxl9VMlnrSQUOdu2AGg38MVFEOP6+e1XnmHwejLZOgQJBANUK5675I8Dz3zo/sITHAaAwIDACK8Lw9vIvEYzfttmKlz+a450ha+IUI6rhy/f6MzoJJnF140MeKG2rwBKqbbMCQQDLQpnOe7qq1UCxhm8Df4PXP1bHBJr88XkgjOjCU9M5/VqmLKCTtCtyHG9ysCtc+r1qUxiNhGyz+D/Wu+bvlR+1AkAhusBDq55FhlbpWfwQiZFwUy5Fa5KSIqR2Y41byG+isZaQs20mC4yRFq8u9uDcOfiyT5COliONFNFBy9d1HRaRAkB0lXDO5Fz/G24N5QPLx9oBHg1R/axAJOjK6Megnp/rBQx3f+ViktbQjsrFx5I3tIHseFj+4tPOrjc/nWsqRCh5AkBPS39LFZTugbdCVuan9iD8M+WgLWg/dyB/eByIt7qyl6eIuqoGWzFobMcu8rr0izbE7ZQBa6Rxq6DhBCZxHENY";
	/*
	 * =================开始=登录==============
	 */
	
	public boolean login(SellerInfomation sellerInfomation, String sellercentralSite) {
		try {
			//打开登录页面
			driver.get(sellercentralSite);
			shotCapture("login0");
			Thread.sleep(3*1000);
			
			//点击右上角登录
			if (existElement(By.id("sign-in-button"))) {
				WebElement signInButton = driver.findElement(By.id("sign-in-button"));
			    signInButton.click();
			    shotCapture("login1");
			    Thread.sleep(3*1000);
			}
			
			//输入账号和密码
		    if (existElement(By.id("ap_email")) || existElement(By.id("ap_password"))) {
		    	
		    	if(existElement(By.id("ap_email"))) {
		    		WebElement ap_email = driver.findElement(By.id("ap_email"));
		    		ap_email.sendKeys(sellerInfomation.getLoginName());
		    		Thread.sleep(3*1000);
		    	}
			    
			    WebElement ap_password = driver.findElement(By.id("ap_password"));
			    ap_password.sendKeys(sellerInfomation.getPassword(privateKey));
			    Thread.sleep(3*1000);

			    shotCapture("login2");
			    WebElement signInSubmit = driver.findElement(By.id("signInSubmit"));
			    signInSubmit.click();
			    Thread.sleep(3*1000); 
			    
			    shotCapture("login3");
			    if (existElement(By.id("auth-captcha-image"))) {
			    	logger.error("!!!captcha image!!!!");
			    	return false;
			    }
			    
			    //输入二步验证
			    if (existElement(By.id("auth-mfa-otpcode"))) {
				    GoogleAuthenticator googleAuthenticator=new GoogleAuthenticator();
				    String twostep=googleAuthenticator.calculateValidationCode(sellerInfomation.getTwoStepCode(privateKey));
				    WebElement auth_mfa_otpcode = driver.findElement(By.id("auth-mfa-otpcode"));
				    auth_mfa_otpcode.sendKeys(twostep);
				    Thread.sleep(3*1000);
				    
				    WebElement auth_signin_button = driver.findElement(By.id("auth-signin-button"));
				    auth_signin_button.click();
				    shotCapture("login4");
				    Thread.sleep(3*1000);
			    }
			    
			    if(existElement(By.id("sc-mkt-picker-switcher-select")))
			    {
			    	shotCapture("login5");
			    	if(existElement(By.id("sc-widget-alert-warning"))) {
			    		WebElement sc_widget_alert_warning = driver.findElement(By.id("sc-widget-alert-warning"));
			    		String warningMessage = sc_widget_alert_warning.getText();
			    		logger.warn("account is not normal {}", warningMessage);
			    	}
			    	return true;
			    }else {
			    	shotCapture("login5");
			    	return false;	
			    }			    
			}else {
				String currentUrl = driver.getCurrentUrl();
				logger.info("检查地址链接是否包含/gp/homepage.html 或者  /home: " + currentUrl.indexOf("/gp/homepage.html")  + " " + currentUrl.indexOf("/home") + " " + currentUrl);
				if (currentUrl.indexOf("/gp/homepage.html") > 0 || currentUrl.indexOf("/home") > 0) {// 登录成功
					return true;
				}
				return false;
			}
		  
		} catch (Exception e) {
			logger.error("Login Failed ", e);
			return false;
		}
	}
	
	/*
	 * ================结束=登录==============
	 */
	/*
	 * =================开始=公用方法==============
	 */
	public void shotCapture(String fileName) {
		try {
			if(browserSetting.isCaptureScreen()) {
				String filePath=String.format("%s/%s.png", browserSetting.getCaptureScreenPath(), fileName);
				ImageIO.write(aShot.takeScreenshot(driver).getImage(),"PNG",new File(filePath));
			}
		} catch (Exception e) {
			logger.error("Capture Screen ERROR", e);
		}
	}
	public boolean existElement(By by) {
		List<WebElement> findElements = driver.findElements(by);
		if (findElements.size()>0) {
			return true;
		}else {
			return false;
		}
	}
	/*
	 * ================结束=公用方法==============
	 */
	/*
	 * ============开始=浏览器管理==============
	 */
	public RemoteWebDriver driver;
	private DesiredCapabilities desiredCapabilities;
	private BrowserSetting browserSetting;
	protected String browserName;
	protected AShot aShot;
	private Logger logger= LoggerFactory.getLogger(getClass());
	
	public RemoteWebDriver startBrowser(String opaqueKey, BrowserSetting browserSetting) {
		try {
			//GeckoDriverService
			//保存至属性
			this.browserSetting=browserSetting;
			logger.info("Start FireFox");
			
			String serverUrl=String.format("http://%s:%d/wd/hub/", browserSetting.getServer(), browserSetting.getPort());
			logger.info("Connect {}", serverUrl);
			
			logger.info("Clear Death Session {}", serverUrl);
			new ActiveRemoteWebDriverSession(new URL(serverUrl), DesiredCapabilities.firefox()).clearDeathSession();
			
			//设置屏幕截图的路径,并判断路径是否存在,不存在则创建
			if(browserSetting.isCaptureScreen())
			{
				ShootingStrategy shootingStrategyViewportPasting = ShootingStrategies.viewportPasting(100);
				aShot = new AShot().shootingStrategy(shootingStrategyViewportPasting);
				
				//判断路径,没有则创建
				File captureScreenPahFile=new File(browserSetting.getCaptureScreenPath());
				if (!captureScreenPahFile.exists()) {
					logger.info("Create Capture Save Path {}", browserSetting.getCaptureScreenPath());
					captureScreenPahFile.mkdirs();
				}
				logger.info("Capture Save Path {}", browserSetting.getCaptureScreenPath());
			}
			
			//设置浏览器的下载路径
			desiredCapabilities = DesiredCapabilities.firefox();
			FirefoxProfile profile = new FirefoxProfile();//allProfiles.getProfile("default");
			profile.setPreference("browser.download.folderList",2);
			profile.setPreference("browser.download.dir",browserSetting.getRemoteBrowserDownloadPath());
			profile.setPreference("browser.download.lastDir",browserSetting.getRemoteBrowserDownloadPath());
			profile.setPreference("browser.download.useDownloadDir",true);
			profile.setPreference("browser.download.manager.showWhenStarting",false);
			profile.setPreference("browser.helperApps.neverAsk.saveToDisk","text/plain,application/octet-stream,application/vnd.ms-excel,text/csv,application/zip,application/exe");
			logger.info("Download Path {}", browserSetting.getRemoteBrowserDownloadPath());
			
			//设置配置,和设置无头
			FirefoxOptions firefoxOptions=new FirefoxOptions();
			firefoxOptions.setProfile(profile);
			firefoxOptions.setHeadless(browserSetting.isHeadless());
			desiredCapabilities.setCapability(FirefoxOptions.FIREFOX_OPTIONS, firefoxOptions);
			
			browserName=desiredCapabilities.getCapability("browserName").toString();
			
			
			//使用配置链接到selenium server,如果是无头浏览器,需要设置浏览器尺寸
			if (opaqueKey!=null) {
				logger.info("Reuse Session {}", opaqueKey);
				
				SessionId sessionId=new SessionId(opaqueKey);
				ActiveHttpCommandExecutor activeHttpCommandExecutor=new ActiveHttpCommandExecutor(sessionId, new URL(serverUrl));
				driver= new RemoteWebDriver(activeHttpCommandExecutor, desiredCapabilities);

				Command command=new Command(sessionId, DriverCommand.GET_CURRENT_URL);
				Response response = activeHttpCommandExecutor.execute(command);
				if (response==null || response.getValue() instanceof WebDriverException) {
					command = new Command(sessionId, DriverCommand.QUIT, ImmutableMap.of());
					response = activeHttpCommandExecutor.execute(command);
					logger.info("Session {} isDeath", opaqueKey);
					driver=null;
					return null;
				}
			}else {
				driver= new RemoteWebDriver(new URL(serverUrl),desiredCapabilities);
				logger.info("New Session {}", driver.getSessionId());
				if(browserSetting.isHeadless())
					driver.manage().window().setSize(new Dimension(1440,900));
			}
			
			Iterator<MarketplaceHandler> marketplaceIterator = marketplaceHandlers.iterator();
			logger.info("Set Driver instance to handler({})", marketplaceHandlers.size());
			while (marketplaceIterator.hasNext()) {
				MarketplaceHandler marketplaceHandler = (MarketplaceHandler) marketplaceIterator.next();
				marketplaceHandler.setDriver(driver);
				marketplaceHandler.setDesiredCapabilities(desiredCapabilities);
				marketplaceHandler.setBrowserSetting(browserSetting);
				marketplaceHandler.setBrowserName(browserName);
				marketplaceHandler.setaShot(aShot);
			}
			logger.info("Start FIREFOX success");	
		} catch (Exception e) {
			logger.error("Start FIREFOX ERROR", e);
		}
		return driver;
	}
	
	public RemoteWebDriver startBrowser(BrowserSetting browserSetting) {
		String sessionId = loadExistSessionId();
		if (sessionId!=null) {
			RemoteWebDriver startBrowser = startBrowser(sessionId, browserSetting);
			if (startBrowser!=null) {
				return startBrowser;
			}
		}	
		RemoteWebDriver startBrowser = startBrowser(null, browserSetting);
		saveSessionId(startBrowser.getSessionId().toString());
		return startBrowser;
	}
	
	private String sessionRecordPath="./";
	public String getSessionRecordPath() {
		return sessionRecordPath;
	}

	public void setSessionRecordPath(String sessionRecordPath) {
		this.sessionRecordPath = sessionRecordPath;
	}

	private String loadExistSessionId() {
		try {
			logger.info("sessionId save {} ",sessionRecordPath);
			File file=new File(sessionRecordPath);
			if(file.exists()){
				BufferedReader bufferedReader=null;
				try {
					bufferedReader=new BufferedReader(new FileReader(file));
					return bufferedReader.readLine();
				} finally {
					if(bufferedReader!=null)bufferedReader.close();
				}
			}
		} catch (Exception e) {
		}
		return null;		
	}
	private void saveSessionId(String sessionId) {
		try {
			File file=new File(sessionRecordPath);
			BufferedWriter bufferedWriter=new BufferedWriter(new FileWriter(file));
			bufferedWriter.write(sessionId);
			bufferedWriter.close();
		} catch (Exception e) {
		}
	}
	
	public void quitBrowser() {
		try {
			driver.quit();	
		} catch (Exception e) {
			logger.error("Quit FIREFOX ERROR", e);
		}		
	}
	/*
	 * ================结束=浏览器管理==============
	 */

}
